package metrictransformer

import (
	ms "gitee.com/shipnet/flogo_metric_store"
	"github.com/mitchellh/mapstructure"
	"github.com/project-flogo/core/data/coerce"
)

type MappingFilterOptions struct {
	Type   string      `mapstructure:"type,required" md:"type,required" json:"type,omitempty"`
	Params interface{} `mapstructure:"params,required" md:"params,required" json:"params,omitempty"`
}

type MappingTransformerOptions struct {
	Type   string      `mapstructure:"type" md:"type,required" json:"type,omitempty"`
	Params interface{} `mapstructure:"params" md:"params,required" json:"params,omitempty"`
}

type Mapping struct {
	Filter       MappingFilterOptions       `mapstructure:"filter,required" md:"filter,required" json:"filter,omitempty"`
	MapID        MappingTransformerOptions  `mapstructure:"mapId,required" md:"mapId,required" json:"mapId,omitempty"`
	MapTimestamp *MappingTransformerOptions `mapstructure:"mapTimestamp" md:"mapTimestamp" json:"mapTimestamp,omitempty"`
	MapValue     *MappingTransformerOptions `mapstructure:"mapValue" md:"mapValue" json:"mapValue,omitempty"`
}

type ActivitySettings struct {
	Mappings []interface{} `md:"mappings" json:"mappings,omitempty"`
}

type Input struct {
	Data ms.MetricData `md:"data" json:"data,omitempty"`
}

func (r *Input) ToMap() map[string]interface{} {
	return map[string]interface{}{
		"data": toMap(r.Data),
	}
}

func (r *Input) FromMap(values map[string]interface{}) error {
	m, err := coerce.ToObject(values["data"])
	if err != nil {
		return err
	}
	data, err := fromMap(m)
	if err != nil {
		return err
	}
	r.Data = *data

	return nil
}

type Output struct {
	Err     string          `md:"err" json:"err,omitempty"`
	Metrics []ms.MetricData `md:"metrics" json:"metrics,omitempty"`
}

func (r *Output) ToMap() map[string]interface{} {
	metrics := make([]map[string]interface{}, len(r.Metrics))
	for idx, m := range r.Metrics {
		metrics[idx] = toMap(m)
	}
	return map[string]interface{}{
		"err":     r.Err,
		"metrics": metrics,
	}
}

func (r *Output) FromMap(values map[string]interface{}) error {
	str, err := coerce.ToString(values["err"])
	if err != nil {
		return err
	}
	r.Err = str

	msData, err := coerce.ToArray(values["metrics"])
	if err != nil {
		return err
	}
	metrics := make([]ms.MetricData, len(msData))
	for idx, m := range msData {
		d, err := coerce.ToObject(m)
		if err != nil {
			return err
		}
		md, err := fromMap(d)
		if err != nil {
			return err
		}
		metrics[idx] = *md
	}
	r.Metrics = metrics

	return nil
}

func toMap(m ms.MetricData) map[string]interface{} {
	return m.ToMap()
}

func fromMap(values map[string]interface{}) (*ms.MetricData, error) {
	return ms.MapToMetricData(values)
}

func toMapping(data interface{}) (Mapping, error) {
	m := Mapping{}
	err := mapstructure.Decode(data, &m)
	return m, err
}
